package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseBaseModel;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.enums.content.TeachPlanEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseMarketService courseMarketService;

    @Autowired
    private CourseBaseService courseBaseService;

    /**
     * 分页查询
     *
     * @param params    {@link PageRequestParams} 分页封装数据
     * @param model     {@link QueryCourseBaseModel} 分页查询封装数据
     * @param companyId {@link Long} 教学机构的id标识
     * @return
     */
    public PageVO queryCourseList(PageRequestParams params, QueryCourseBaseModel model, Long companyId) {

        // 1.判断关键数据
        // 分页数据 判断int合理性 ：要求数据不能为负数
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }


        if (ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException("公司id不能为空");
        }


        // 2.构建分页对象数据
        Page<CourseBase> page = new Page<>(params.getPageNo(), params.getPageSize());

        // 3.构建查询条件对象
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        // 课程名称的条件：like
        // 完整版
        // if (StringUtil.isNotBlank(model.getCourseName())) {
        //     queryWrapper.like(CourseBase::getName, model.getCourseName());
        // }

        // 简略版
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()), CourseBase::getName, model.getCourseName());

        // 课程审核的条件：eq
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()), CourseBase::getAuditStatus, model.getAuditStatus());

        // 机构数据隔离条件
        if (ObjectUtils.isEmpty(model.getMark())) {
            queryWrapper.eq(CourseBase::getCompanyId, companyId);
        }


        // 4.查询数据
        Page<CourseBase> pageResult = this.page(page, queryWrapper);

        List<CourseBase> records = pageResult.getRecords();

        long total = pageResult.getTotal();

        // 5.将数据po转为dto数据
        List<CourseBaseDTO> dtos = Collections.EMPTY_LIST;
        if (!(CollectionUtils.isEmpty(records))) {
            dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }

        // 6.构建返回数据PageVO
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());

        return pageVO;
    }

    /*新增数据
     * 业务分析：
     *   1.判断关键数据
     *       关键数据都是必要数据，由前端传入
     *           前端：form表单中标红星为必要数据
     *           数据库：非空
     *           api文档：数据有些是必要的（Yapi）
     *   2.将数据进行转换
     *       dto->po (mapstruct)
     *   3.是否要给数据赋值默认内容
     *       需要在后端或者数据库来填写
     *           status：是否删除
     *           create_date:数据创建时间（mp）
     *           create_people：创建人
     *           audit_status:课程审核状态
     *               对于新增数据状态：未提交
     *               参考：CourseAuditEnum
     *   4.保存数据到数据库中
     *       课程基础信息数据（1）
     *       课程营销（2）
     *       PS：保存有先后顺序--课程营销中要保存courseBaseId值
     *   5.判断对数据操作的结果
     *   6.将数据库最新的数据转为dto并返回
     * */
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {

        // 1.判断关键数据(封装方法：ctrl+alt+M)
        verifyCourseMsg(dto);


        //  2.将数据进行转换
        //      dto->po (mapstruct)
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);


        //  3.是否要给数据赋值默认内容
        //      需要在后端或者数据库来填写
        //          status：是否删除
        //          create_date:数据创建时间（mp）
        //          create_people：创建人(前期无需关系)
        //          audit_status:课程审核状态
        //              对于新增数据状态：未提交
        //              参考：CourseAuditEnum
        courseBase.setStatus(CommonEnum.USING_FLAG.getCodeInt());
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());


        //  4.保存数据到数据库中
        //  5.判断对数据操作的结果
        //      课程基础信息数据（1）
        // 保存完信息后，id会自动回填（MP）
        boolean baseResult = this.save(courseBase);

        if (!baseResult) {
            throw new RuntimeException("保存课程基础信息失败");
        }


        //      课程营销（2）
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(dto.getCharge());
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {
            BigDecimal price = dto.getPrice();
            courseMarket.setPrice(price.floatValue());
        }

        //      PS：保存有先后顺序--课程营销中要保存courseBaseId值
        boolean marketResult = courseMarketService.save(courseMarket);
        if (!marketResult) {
            throw new RuntimeException("课程营销信息保存失败");
        }


        //  6.将数据库最新的数据转为dto并返回
        // 如果有些数据是数据库生成的，数据模型在不通过查询方式是无法获得最新的数据库数据内容
        CourseBase po = this.getById(courseBase.getId());
        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        resultDTO.setPrice(dto.getPrice());
        resultDTO.setCharge(dto.getCharge());

        return resultDTO;
    }

    /**
     * 判断必须字段不能为空
     *
     * @param dto
     * @return
     */
    private String verifyCourseMsg(CourseBaseDTO dto) {
        // 1.判断关键数据
        //      关键数据都是必要数据，由前端传入
        //          前端：form表单中标红星为必要数据
        //          数据库：非空
        //          api文档：数据有些是必要的（Yapi）
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            // 业务异常：程序员在做业务判断时，数据有问题。
            // 异常：
            //    1.终止程序
            //    2.传递错误信息
            //    3.使用运行时异常来抛出
            //        运行时异常不需在编译期间处理
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }

        if (StringUtil.isBlank(dto.getName())) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }

        if (StringUtil.isBlank(dto.getMt())) {
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }

        if (StringUtil.isBlank(dto.getSt())) {
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }

        if (StringUtil.isBlank(dto.getGrade())) {
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }

        if (StringUtil.isBlank(dto.getTeachmode())) {
            ExceptionCast.cast(ContentErrorCode.E_120006);
        }

        if (StringUtil.isBlank(dto.getUsers())) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }


        String charge = dto.getCharge();
        if (StringUtil.isBlank(charge)) {
            ExceptionCast.cast(ContentErrorCode.E_120104);
        }

        // 判断课程是否收费，如果收费判断是否有价格，没有价格，将会出错
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            if (ObjectUtils.isEmpty(dto.getPrice())) {
                ExceptionCast.cast(ContentErrorCode.E_120104);
            }
        }
        return charge;
    }


    /*
     * 业务分析：新增课程
     *   1.判断关键数据
     *       courseBaseId  companyId
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *       课程营销
     *   3.查询数据并转为dto返回
     *
     * */
    public CourseBaseDTO getByCourseId(Long courseBaseId, Long companyId) {
        //判断课程id
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("课程id不能为空");
        }

        //判断机构id
        if (ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException("课程id不能为空");
        }

        //获取前端传来的课程id获取课程对象
        CourseBase courseBase = this.getById(courseBaseId);

        //判断是否存在
//        if (courseBase.getCompanyId().equals()) {
//
//        }

        //判断是否是同一家教学机构
        if (!(courseBase.getCompanyId().equals(companyId))) {
            throw new RuntimeException("该课程不属于本机构");
        }

        //判断是否删除
        if (CommonEnum.DELETE_FLAG.getCode().equals(courseBase.getStatus())) {
            throw new RuntimeException("该课程已被删除");
        }

        //课程营销
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        LambdaQueryWrapper<CourseMarket> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseMarket::getCourseId, courseBaseId);
        CourseMarket market = courseMarketService.getOne(queryWrapper);
        courseBaseDTO.setCharge(market.getCharge());
        Float price = market.getPrice();
        courseBaseDTO.setPrice(BigDecimal.valueOf(price));


        return courseBaseDTO;
    }


    /*
     *修改代码
     * 业务分析：
     *   1.判断关键数据
     *       可以使用添加的判断
     *       修改时：课程id是必须存在
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *           判断课程审核状态：未提交、审核未通过
     *       课程营销
     *   3.修改数据内容
     *       课程基础信息表
     *           有些内容是不容修改的：courseBaseId、companyid、auditstatus、status
     *       课程营销数据表
     *           charge price
     *        修改数据时要判断修改后结果
     *
     *   4.返回前端最新的数据库的数据并封装为dto返回
     *
     * */
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {
        //判断必须字段不能为空
        verifyCourseMsg(dto);

        //判断课程id
        if (ObjectUtils.isEmpty(dto.getCourseBaseId())) {
            throw new RuntimeException("课程id不能为空");
        }

        //创建课程po对象
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);

        //判断是否是同一家教学机构
    /*    LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseBase::getCompanyId, dto.getCompanyId());
        CourseBase base = this.getOne(wrapper);
        if ((base.getCompanyId().equals(dto.getCompanyId()))) {
            throw new RuntimeException("不是一家机构，无法操作");
        }*/
        //判断是否删除
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            throw new RuntimeException("课程已删除，无法操作");
        }

        //判断审核状态
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(courseBase.getAuditStatus())
                || CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(courseBase.getAuditStatus())
                || CourseAuditEnum.AUDIT_UNLINE_STATUS.getCode().equals(courseBase.getAuditStatus())) {
            throw new RuntimeException("当前状态不可修改");
        }

        //保存课程对象
        boolean updateById = courseBaseService.updateById(courseBase);
        if (!updateById) {
            throw new RuntimeException("修改课程失败");
        }

        //课程营销
        //CourseMarket courseMarket = new CourseMarket();

        LambdaQueryWrapper<CourseMarket> queryWrapper = new LambdaQueryWrapper<>();
        if (dto.getCourseBaseId() != null) {
            queryWrapper.eq(CourseMarket::getCourseId, dto.getCourseBaseId());
        }
        CourseMarket courseMarket = courseMarketService.getOne(queryWrapper);

        courseMarket.setCharge(dto.getCharge());
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {
            BigDecimal price = dto.getPrice();
            courseMarket.setPrice(price.floatValue());
        }

        //      保存营销数据
        boolean marketResult = courseMarketService.updateById(courseMarket);
        if (!marketResult) {
            throw new RuntimeException("课程营销信息保存失败");
        }

        //  6.将数据库最新的数据转为dto并返回
        // 如果有些数据是数据库生成的，数据模型在不通过查询方式是无法获得最新的数据库数据内容
        CourseBase po = this.getById(courseBase.getId());
        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        resultDTO.setPrice(dto.getPrice());
        resultDTO.setCharge(dto.getCharge());

        return resultDTO;
    }

    /**
     * 删除代码
     *
     * @param courseBaseId 课程对象的id
     * @param companyId    教育机构的id
     */
    @Transactional
    public void removeCourseBase(Long courseBaseId, Long companyId) {
        //判断课程id
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("课程id不能为空");
        }

        //判断教育机构id
        if (ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException("教育机构id不能为空");
        }

        //获取课程对象
        CourseBase courseBase = courseBaseService.getById(courseBaseId);

        //判断审核状态
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.equals(courseBase.getAuditStatus())
                || CourseAuditEnum.AUDIT_PASTED_STATUS.equals(courseBase.getAuditStatus())
                || CourseAuditEnum.AUDIT_PUBLISHED_STATUS.equals(courseBase.getAuditStatus())) {
            throw new RuntimeException("状态不匹配，无法删除");
        }

        //po转化未dto
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        courseBase.setAuditStatus(CommonEnum.DELETE_FLAG.getCode());

        boolean removeById = courseBaseService.removeById(courseBaseDTO.getCourseBaseId());
        if (!removeById) {
            throw new RuntimeException("删除失败");
        }

    }


    /*测试无误
     * 业务分析：
     *   1.判断关键数据
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *           判断审核状态
     *   3.修改课程审核状态
     *       已提交
     * */
    @Transactional
    public void commitCourseBase(Long courseId, Long companyId) {
        //判断前端传来的课程id是否为空
        if (ObjectUtils.isEmpty(courseId) ||
                ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(ContentErrorCode.E_120009);
        }

        CourseBase courseBase = courseBaseService.getById(courseId);


        //判断是否是同一家机构
        if (!(courseBase.getCompanyId().equals(companyId))) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }


        //判断是否删除
        if (TeachPlanEnum.FIRST_PARENTID_FLAG.equals(courseBase.getStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120010);
        }

        //判断审核状态(不能是已提交，审核通过，课程已发布)
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.equals(courseBase.getAuditStatus())) {

            ExceptionCast.cast(ContentErrorCode.E_120015);
        }

        //修改课程计划的审核状态为已提交
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());

        boolean updateById = courseBaseService.updateById(courseBase);
        if (!updateById) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }





    /*
     * 业务分析：
     *   1.判断关键数据
     *       auditMind  auditStatus  courseid
     *
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否删除
     *           判断审核状态
     *               必须为：已提交
     *       审核状态
     *           运营平台只能给课程审核状态赋值：审核通过、审核未通过
     *   3.修改课程审核信息
     *       auditMind  auditStatus  auditNum（每次+1）
     * */
    @Transactional
    public void approveCourse(CourseBaseDTO dto) {
        //判断课程的审核状态
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(dto.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(dto.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(dto.getAuditStatus())) {

            ExceptionCast.cast(ContentErrorCode.E_120015);
        }

        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(dto.getAuditStatus())) {
            //审核通过
            dto.setAuditStatus(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode());
        } else {
            //审核未通过
            dto.setAuditStatus(CourseAuditEnum.AUDIT_DISPAST_STATUS.getCode());
        }

        //dto转化为po
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);

        //判断更改是否成功
        boolean updateCourse = courseBaseService.updateById(courseBase);
        if (!updateCourse) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }
}
